﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ProcessFile
{
  public  class ConvertStackup2ADDesignRule
    {
        string viaTemp = "SELECTION=FALSE|LAYER=UNKNOWN|LOCKED=FALSE|POLYGONOUTLINE=FALSE|USERROUTED=TRUE|UNIONINDEX=0|RULEKIND=RoutingVias|NETSCOPE=AnyNet|LAYERKIND=SameLayer|SCOPE1EXPRESSION=All|SCOPE2EXPRESSION=All|NAME=ICD Stackup Planner {0}|ENABLED=TRUE|PRIORITY={1}|COMMENT= |UNIQUEID={2}|DEFINEDBYLOGICALDOCUMENT=FALSE|HOLEWIDTH={3}|WIDTH={4}|VIASTYLE=Through Hole|MINHOLEWIDTH={3}|MINWIDTH={5}|MAXHOLEWIDTH={6}|MAXWIDTH={7}¶";

        private string clearanceTemp =
            "SELECTION=FALSE|LAYER=UNKNOWN|LOCKED=FALSE|POLYGONOUTLINE=FALSE|USERROUTED=TRUE|UNIONINDEX=0|RULEKIND=Clearance|NETSCOPE=DifferentNets|LAYERKIND=SameLayer|SCOPE1EXPRESSION=All|SCOPE2EXPRESSION=All|NAME=ICD Stackup Planner Clearance|ENABLED=TRUE|PRIORITY=2|COMMENT= |UNIQUEID={0}|DEFINEDBYLOGICALDOCUMENT=FALSE|GAP={1}¶";
       string traceWidthTemp="SELECTION=FALSE|LAYER=UNKNOWN|LOCKED=FALSE|POLYGONOUTLINE=FALSE|USERROUTED=TRUE|UNIONINDEX=0|RULEKIND=Width|NETSCOPE=AnyNet|LAYERKIND=SameLayer|SCOPE1EXPRESSION={4}|SCOPE2EXPRESSION=All|NAME=ICD Stackup Planner Width|ENABLED=TRUE|PRIORITY=2|COMMENT= |UNIQUEID={0}|DEFINEDBYLOGICALDOCUMENT=FALSE|MAXLIMIT={1}|MINLIMIT={2}|PREFEREDWIDTH={3}¶";
       string hedaerDiffPairTemp ="SELECTION=FALSE|LAYER=UNKNOWN|LOCKED=FALSE|POLYGONOUTLINE=FALSE|USERROUTED=TRUE|UNIONINDEX=0|RULEKIND=DiffPairsRouting|NETSCOPE=AnyNet|LAYERKIND=SameLayer|SCOPE1EXPRESSION={0}|SCOPE2EXPRESSION=All|NAME=ICD Stackup Planner {1}|ENABLED=TRUE|PRIORITY=1|COMMENT= |UNIQUEID={2}|DEFINEDBYLOGICALDOCUMENT=FALSE|MAXLIMIT={3}|MINLIMIT={4}|MOSTFREQGAP={5}|";
        StkFile _stkFile;
        string _unit;
        string key = "ICDABCDEF";
        public ConvertStackup2ADDesignRule(string fileStkPath)
        {
            _stkFile = new StkFile(fileStkPath);
            _unit = _stkFile._lines[_stkFile.UnitLine];


        }
        public  decimal  MinWidth
        {
            get { return 4; }
        }
        public decimal MAXUNCOUPLEDLENGTH
        {
            get {
                return 300;
            }
        }
        public decimal MaxLimitInDiffPair
        {
            get {
                return 30;
            }
        }
        public decimal MostFregGap
        {
            get {
                return 12;
            }
             
        }
        public decimal MinLimitInDiffPair
        {
            get
            {
                return 12;
            }
        }
        public  decimal  MaxWidth
        {
            get { return 15; }
        }
        public string Unit
        {
            get
            {
                return _stkFile._lines[_stkFile.UnitLine];
            }
        }
        public int GetWidth(string type)
        {
            if (type=="PTH" || type=="Buried")
            {
                return 20;
            }
            return 18;
        }
        public int GetMaxWidth(string type)
        {
            if (type == "PTH" || type == "Buried")
            {
                return 35;
            }
            return 20;
        }
        public string FormatNumber(decimal number)
        {
                 return string.Format("{0}{1}", number.ToString("G29"), "mil");
        }
        public string FormatAndConvertNumber(decimal number)
        {
            if (_unit=="um")
            {
                number = number / 25.4m;
            }
            return FormatNumber(number);
        }
        public decimal ConvertUmToMil(decimal number)
        {
            if (_unit == "um")
            {
                number = number / 25.4m;
            }
            return  number;
        }
        public  decimal  GetMinClearance()
        {
            decimal minClearance = decimal.MaxValue;
            for (int i = _stkFile.UnitLine+1; i < _stkFile._lines.Length; i++)
            {
                if (_stkFile._lines[i].ToLower().IndexOf("via")==0||_stkFile._lines[i].ToLower()=="*")
                {
                    break;
                }
                string[] itemDiffPair = _stkFile._lines[i].Split(Common.SplipChar);
                string strClearance = itemDiffPair[Common.DiffPairClearanceIndex];
                decimal currentClearance = Convert.ToDecimal(strClearance);
                if (currentClearance<minClearance)
                {
                    minClearance = currentClearance;
                }
            }
            if (minClearance==decimal.MaxValue)
            {
                return 0;
            }
            return minClearance;
        }
        public decimal GetMinTraceWidth()
        {
            decimal minClearance = decimal.MaxValue;
            for (int i = _stkFile.UnitLine + 1; i < _stkFile._lines.Length; i++)
            {
                if (_stkFile._lines[i].ToLower().IndexOf("via") == 0 || _stkFile._lines[i].ToLower()=="*")//update
                {
                    break;
                }
                string[] itemDiffPair = _stkFile._lines[i].Split(Common.SplipChar);
                string strClearance = itemDiffPair[Common.DiffPairWidthIndex];
                decimal currentClearance = Convert.ToDecimal(strClearance);
                if (currentClearance < minClearance)
                {
                    minClearance = currentClearance;
                }
            }
            if (minClearance == decimal.MaxValue)
            {
                return 0;
            }
            return minClearance;
        }
        public string GetTraceWidthConvert()
        {
            string expression = SCOPE1EXPRESSION();
            string str = string.Format(traceWidthTemp, key, FormatNumber(MaxWidth), FormatNumber(MinWidth), FormatAndConvertNumber(GetMinTraceWidth()), expression);
            key = Common.NxtKeyCode(key);
            return str;
        }
        public  string GetClearanceConvert()
        {
            string str = string.Format(clearanceTemp, key, FormatAndConvertNumber(GetMinClearance()));
            return str;
        }
        #region get diff pair
        public string GetDiffPair()
        {
            string str="";
            int signCount = SignLayerCount();
            int startDiffPair = _stkFile.UnitLine+1;
            int viaIndex = _stkFile.ViaLineIndex;
            if ((viaIndex - startDiffPair) % signCount == 0)
            {
                int diffPairNumber = (viaIndex - startDiffPair) / signCount;
                for (int i = diffPairNumber-1; i >=0; i--)
                {
                    str += GetDiffPair(startDiffPair + signCount * i) + "¶\n";
                }
            }
            return str;
        }
       
        public  string GetDiffPair(int fromIndex)
        {
            string str = "";
            //get Most Layer MostFregGap
            decimal mostFreGap = Convert.ToDecimal(_stkFile._lines[fromIndex + 1].Split(Common.SplipChar)[Common.DiffPairClearanceIndex]);
                string[] item = _stkFile._lines[fromIndex].Split(Common.SplipChar);
            //header
                decimal clr = Convert.ToDecimal(item[Common.DiffPairClearanceIndex]);
                decimal width = Convert.ToDecimal(item[Common.DiffPairWidthIndex]);
                string expression = SCOPE1EXPRESSION();
                str += string.Format(hedaerDiffPairTemp, expression, item[Common.DiffPairNameIndex], key, FormatNumber(MaxLimitInDiffPair), FormatAndConvertNumber(clr), FormatAndConvertNumber(mostFreGap));
                key = Common.NxtKeyCode(key);
           //top layer
        
         
            str += GetTopLayerConvert(clr, width);
            //Mid Layer
            string[] it = _stkFile._lines[fromIndex + 1].Split(Common.SplipChar);
            decimal w = Convert.ToDecimal(it[Common.DiffPairWidthIndex]);
           
            for (int i=1; i <=30; i++)
            {
                if (i<=SignLayerCount()-2)
                {
                    string[] itnew = _stkFile._lines[fromIndex + i].Split(Common.SplipChar);
                    w = Convert.ToDecimal(itnew[Common.DiffPairWidthIndex]);
                    mostFreGap = Convert.ToDecimal(itnew[Common.DiffPairClearanceIndex]);
                }
                str += MidLayer(w, mostFreGap, i);
            }
            //bottom layer
             item = _stkFile._lines[fromIndex].Split(Common.SplipChar);
             clr = Convert.ToDecimal(item[Common.DiffPairClearanceIndex]);
             width = Convert.ToDecimal(item[Common.DiffPairWidthIndex]);
             str += GetBottomLayerConvert(clr, width);
             //MAXUNCOUPLEDLENGTH=500mil
             str += string.Format("MAXUNCOUPLEDLENGTH={0}", FormatNumber(MAXUNCOUPLEDLENGTH));
            return str;

        }
        public  string GetLayerConvert(string width)
        {
            int signCount = SignLayerCount();
            int unitIndex = _stkFile.UnitLine;
            int viaIndex = _stkFile.ViaLineIndex;
            if (unitIndex - viaIndex > 1)
            {

            }
            return "";
        }
        public  string GetTopLayerConvert(decimal  prefGrap,decimal  prefWidth)
        {
            string str = string.Format("TOPLAYER_PREFGAP={0}|TOPLAYER_MINWIDTH={1}|TOPLAYER_MAXWIDTH={2}|TOPLAYER_PREFWIDTH={3}|", FormatAndConvertNumber(prefGrap), FormatNumber(MinWidth), FormatNumber(MaxWidth), FormatAndConvertNumber(prefWidth));
            return str;
        }
        public string GetBottomLayerConvert(decimal prefGrap, decimal prefWidth)
        {
            string str = string.Format("BOTTOMLAYER_PREFGAP={0}|BOTTOMLAYER_MINWIDTH={1}|BOTTOMLAYER_MAXWIDTH={2}|BOTTOMLAYER_PREFWIDTH={3}|", FormatAndConvertNumber(prefGrap), FormatNumber(MinWidth), FormatNumber(MaxWidth), FormatAndConvertNumber(prefWidth));
            return str;
        }
        public  string MidLayer(decimal  prefWidth,decimal  mostLayerPre,int count)
        {
            string str = string.Format("MIDLAYER{0}_PREFGAP={4}|MIDLAYER{0}_MINWIDTH={1}|MIDLAYER{0}_MAXWIDTH={2}|MIDLAYER{0}_PREFWIDTH={3}|", count,
                                       FormatNumber(MinWidth), FormatNumber(MaxWidth), FormatAndConvertNumber(prefWidth),FormatAndConvertNumber(mostLayerPre));
            return str;
        }
        public string SCOPE1EXPRESSION()
        {
            string expession = "";
            for (int i = 0; i < _stkFile.UnitLine; i++)
            {
                string[] item = _stkFile._lines[i].Split(Common.SplipChar);
                if (item[Common.DescriptionIndex].ToLower() == "signal")
                {
                    expession += string.Format("OnLayer('{0}') AND ", item[Common.LayerNameIndex]);
                }
            }
            if (expession.Length>5)
            {
                expession ="("+expession.Substring(0, expession.Length - 5)+")";
            }
            return expession;
        }
        public  int SignLayerCount()
        {
            int count = 0;
            for (int i = 0; i < _stkFile.UnitLine; i++)
            {
                string[] item = _stkFile._lines[i].Split(Common.SplipChar);
                if (item[Common.DescriptionIndex].ToLower() == "signal")
                {
                    count++;
                }
            }
            return count;
        }
           
        #endregion
        #region convert Via
       
        public string GetViaConvert()
        {
            string str = "";
            int viaIndex = _stkFile.ViaLineIndex;
            if (viaIndex>0)
            {
                for (int i = viaIndex; i < _stkFile._lines.Length; i++)
                {
                    if (_stkFile._lines[i].ToLower().IndexOf("via")==0)
                    {
                        str += GetViaByLine(_stkFile._lines[i], (i + 1 - viaIndex))+"\n";    
                    }
                    
                }
            }

            return str; 
        }
        public string GetViaByLine(string line, int count)
        {
            string[] item = line.Split(Common.SplipChar);
            string name = item[Common.ViaTypeIndex]+" " + item[Common.ViaNameIndex];
          
           decimal holeSize =ConvertUmToMil( Convert.ToDecimal( item[Common.ViaHoleSizeIndex]));
           decimal tolerance = ConvertUmToMil(Convert.ToDecimal(item[Common.ViaToleranceIndex]));
                int width   =GetWidth(item[Common.ViaTypeIndex]);
                int maxWidth =GetMaxWidth(item[Common.ViaTypeIndex]);
            decimal maxHoleWidth=tolerance+holeSize;
            decimal minWidth=maxHoleWidth+8;
            string data = string.Format(viaTemp, name, count, key, FormatNumber(holeSize), FormatNumber(width), FormatNumber(minWidth), FormatNumber(maxHoleWidth), FormatNumber(maxWidth));
            key = Common.NxtKeyCode(key);
            return data;

        }
#endregion 
        #region convert
        public string ConvertADDesignRule()
        {
            string str = "";
            str += GetClearanceConvert()+"\n";
            str += GetTraceWidthConvert()+"\n";
            str += GetViaConvert();
            str += GetDiffPair();
            return str;
        }
        #endregion
    }
}
